package com.message.push.provider.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.util.StringUtils;

@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "通用返回。当调用正常时，返回的具体信息在body中。如果发生错误，body大多数情况下为空。")
public class Result<T> {

    public static <T> Result<T> build(final T body) {
        return new Result<>(body);
    }

    public static <T> Result<T> build(final Class<T> clazz) {
        return new Result<>();
    }

    @Schema(description = "时间戳", requiredMode = Schema.RequiredMode.REQUIRED, example = "145645344445")
    private final long ts = System.currentTimeMillis();

    @Schema(description = "错误码。0或200表示没有错误, 小于1000时，错误代码和HttpStatus代码相对应", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
    private int code = 200;

    @Schema(description = "消息。一般是错误消息", example = "Argument of method is not valid：xxxxx")
    private String message = null;

    @Schema(description = "消息详情。一般是错误消息详情")
    private String details = null;

    @Schema(description = "返回的具体信息。如果发生错误，body大多数情况下为空。注意：body有可能为简单类型。")
    private T body = null;

    public Result() {
        super();
    }

    public Result(final int code, final String message, final String details) {
        this.code = code;
        this.message = message;
        this.details = details;
    }

    public Result(final int code, final Throwable exception) {
        this.code = code;
        this.exception(exception);
    }

    public Result(final T body) {
        this.body = body;
    }

    public Result<T> body(final T body) {
        this.body = body;
        return this;
    }

    public Result<T> code(final int code) {
        this.code = code;
        return this;
    }

    public Result<T> details(final String details) {
        this.details = details;
        return this;
    }

    public Result<T> exception(final Throwable exception) {
        this.setException(exception);
        return this;
    }

    public Result<T> message(final String message) {
        this.message = message;
        return this;
    }

    @Schema(hidden = true)
    public void setException(final Throwable exception) {
        this.message = StringUtils.hasLength(exception.getMessage()) ? exception.getMessage() : exception.toString();
        Throwable t0 = exception.getCause();
        final StringBuilder sb = new StringBuilder();
        sb.append(exception.toString());
        while (t0 != null) {
            sb.append("\r");
            sb.append("Caused by: ");
            sb.append(t0.toString());
            t0 = t0.getCause();
        }
        this.details = sb.toString();
    }

    public T getBody() {
        return this.body;
    }

    public void setBody(final T body) {
        this.body = body;
    }

    public int getCode() {
        return this.code;
    }

    public void setCode(final int code) {
        this.code = code;
    }

    public String getMessage() {
        return this.message;
    }

    public void setMessage(final String message) {
        this.message = message;
    }

    public String getDetails() {
        return this.details;
    }

    public void setDetails(final String details) {
        this.details = details;
    }

    public long getTs() {
        return this.ts;
    }

}
